package com.yupi.lkzyoj.judge.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yupi.lkzyoj.exception.BusinessException;
import com.yupi.lkzyoj.judge.codeSandBox.ICodeSandBox;
import com.yupi.lkzyoj.judge.codeSandBox.model.ExecuteCodeRequest;
import com.yupi.lkzyoj.judge.codeSandBox.model.ExecuteCodeResponse;
import com.yupi.lkzyoj.judge.service.JudgeService;
import com.yupi.lkzyoj.judge.strategy.JudgeStrategy;
import com.yupi.lkzyoj.judge.strategy.JudgeStrategyManager;
import com.yupi.lkzyoj.mapper.QuestionSubmitMapper;
import com.yupi.lkzyoj.model.dto.question.JudgeCase;
import com.yupi.lkzyoj.model.dto.question.JudgeConfig;
import com.yupi.lkzyoj.model.dto.questionsubmit.JudgeInfo;
import com.yupi.lkzyoj.model.entity.Question;
import com.yupi.lkzyoj.model.entity.QuestionSubmit;
import com.yupi.lkzyoj.model.enums.QuesitonSubmitJudgeInfoEnum;
import com.yupi.lkzyoj.model.enums.QuestionSubmitStatusEnum;
import com.yupi.lkzyoj.service.QuestionService;
import com.yupi.lkzyoj.service.QuestionSubmitService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
public class JudgeServiceImpl implements JudgeService {

    @Resource
    private QuestionService questionService;

    @Resource
    private QuestionSubmitService questionSubmitService;

    @Resource
    private ICodeSandBox sandBox;

    @Override
    public QuestionSubmit doJudge(Long questionSubmitId) {
        //System.out.println("sandbox:" + sandBox.toString());

        // 1.获取提交记录和对应的问题记录
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);
        Question question = questionService.getById(questionSubmit.getQuestionId());


        // 2.判断提交的状态是否需要进行判题
        if (questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.RUNNING.getValue())) {
            throw new RuntimeException("题目判题判题中");
        }


        // 设置判题状态为判题中
        LambdaUpdateWrapper<QuestionSubmit> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(QuestionSubmit::getStatus, QuestionSubmitStatusEnum.RUNNING.getValue());
        wrapper.eq(QuestionSubmit::getId, questionSubmitId);
        questionSubmitService.update(wrapper);

        System.out.println("判题中题目状态：" + questionSubmitService.getById(questionSubmitId).toString());


        // 获取输入输出用例列表
        List<JudgeCase> caseList = JSONUtil.toList(question.getJudgeCase(), JudgeCase.class);
        ArrayList<String> inputList = new ArrayList<>();
        ArrayList<String> outputList = new ArrayList<>();

        caseList.stream().forEach(judgeCase -> {
            inputList.add(judgeCase.getInput());
            outputList.add(judgeCase.getOutput());
        });

        JudgeStrategy judgeStrategy = JudgeStrategyManager.choice(questionSubmit.getLanguage());

        ExecuteCodeResponse res = judgeStrategy.doStrategy(new ExecuteCodeRequest(questionSubmit.getCode(), questionSubmit.getLanguage(), inputList), sandBox);

        // 判断执行结果信息
        System.out.println("执行结果:" + res);

        List<String> resOutputList = res.getOutputList();
        String message = res.getMessage();
        Integer status = res.getStatus();
        JudgeInfo judgeInfo = res.getJudgeInfo();

        //判断答案
        // 结果是否正确标识
        Boolean flag = true;
        QuesitonSubmitJudgeInfoEnum resJudgeInfo = QuesitonSubmitJudgeInfoEnum.Accepted;

        // TODO 根据响应的不同状态码 设置提交的不同状态
        if (res.getStatus().equals(300)) {
            // 根据响应的不同状态码 设置提交的不同状态
            // 编译错误
            flag = false;
            resJudgeInfo = QuesitonSubmitJudgeInfoEnum.COMPILE_ERROR;
        }

        if (res.getStatus().equals(301)) {
            //    判题状态正确
            flag = false;
            resJudgeInfo = QuesitonSubmitJudgeInfoEnum.WRONG_ANSWER;
        }


        // 判断执行结果的响应长度是否和测试用例的预期结果个数相同
        if (flag && (resOutputList.size() != outputList.size())) {
            flag = false;
            resJudgeInfo = QuesitonSubmitJudgeInfoEnum.WRONG_ANSWER;
        }
        // 判断每个样例点的执行结果是否相同
        if (flag) {
            for (int i = 0; i < resOutputList.size(); i++) {
                if (!resOutputList.get(i).equals(outputList.get(i))) {
                    flag = false;
                    resJudgeInfo = QuesitonSubmitJudgeInfoEnum.WRONG_ANSWER;
                    break;
                }
            }
        }
        // 判断内存和耗时是否超出
        JudgeConfig judgeConfig = JSONUtil.toBean(question.getJudgeConfig(), JudgeConfig.class);
        if (flag && judgeConfig.getMemoryLimit() < res.getJudgeInfo().getMemory()) {
            resJudgeInfo = QuesitonSubmitJudgeInfoEnum.MEMORY_LIMIT_EXCEEDED;
            flag = false;
        }
        if (flag && judgeConfig.getTimeLimit() < res.getJudgeInfo().getTime()) {
            resJudgeInfo = QuesitonSubmitJudgeInfoEnum.TIME_LIMIT_EXCEEDED;
            flag = false;
        }


        // 更具执行结果设置提交结果状态
        //wrapper.set(QuestionSubmit::getStatus, QuestionSubmitStatusEnum.SUCCESS.getValue());
        wrapper.clear();
        wrapper.eq(QuestionSubmit::getId, questionSubmitId);
        if (resJudgeInfo.getText().equals("成功")) {
            wrapper.set(QuestionSubmit::getStatus, 2);
            wrapper.set(QuestionSubmit::getJudgeInfo, JSONUtil.toJsonStr(new JudgeInfo(resJudgeInfo.getText(), res.getJudgeInfo().getMemory(), res.getJudgeInfo().getTime())));
        } else {
            wrapper.set(QuestionSubmit::getStatus, 3);
            wrapper.set(QuestionSubmit::getJudgeInfo, JSONUtil.toJsonStr(new JudgeInfo(resJudgeInfo.getText(), 0L, 0L)));
        }
        // TODO judgeInfo写入
        questionSubmitService.update(wrapper);


        return questionSubmitService.getById(questionSubmitId);
    }

}
